package org.goldenport.g3

import java.util.Properties
import java.io._
import java.net.URL
import java.sql.DriverManager
import org.apache.http.{HttpHost, HttpEntity, HttpResponse, HttpStatus}
import org.apache.http.client._
import org.apache.http.client.methods._
import org.apache.http.params.BasicHttpParams
import org.apache.http.conn.scheme.SchemeRegistry
import org.apache.http.impl.client.DefaultHttpClient
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager
import com.asamioffice.goldenport.text.UString.notNull
import org.apache.http.entity.StringEntity
import com.asamioffice.goldenport.io.{ UIO, UURL }
import org.goldenport.g3.messages.http
import org.goldenport.g3.events.http._
import org.goldenport.g3.adapters.{G3WebSocketDriver, NullWebSocketDriver}
import org.goldenport.g3.jetty.{JettyWebSocketDriver, JettyWebSocket}

/**
 * @since   Aug. 12, 2010
 * @version Nov. 22, 2010
 * @author  ASAMI, Tomoharu
 */
abstract class G3Platform {
  def open() {
  }

  def close() {
  }

  def openJdbcConnection(
    uri: String, username: String, password: String, driver: String): java.sql.Connection = {
    if (notNull(driver)) {
      Class.forName(driver)
    }
    val props = new Properties()
    props.put("user", username)
    props.put("password", password)
    val conn = DriverManager.getConnection(uri, props)
    conn.setAutoCommit(false)
    conn
  }

  def httpGet(get: http.GET): G3Event
  def httpPut(put: http.PUT): G3Event
  def httpPost(post: http.POST): G3Event
  def httpDelete(delete: http.DELETE): G3Event
  def httpMkcol(mkcol: http.MKCOL): G3Event
  def httpCopy(copy: http.COPY): G3Event
  def httpMove(move: http.MOVE): G3Event
  def urlFetchString(url: URL, encoding: String): String

  def createWebSocketDriver(path: String): G3WebSocketDriver = {
    NullWebSocketDriver
  }

  def logInfo(o: AnyRef, message: Any, data: Any = None)
  def logEnter(o: AnyRef, name: String, message: Any, data: Any = None)
  def logLeave(o: AnyRef, name: String, message: Any, data: Any = None)
  def logDebug(o: AnyRef, message: Any, data: Any = None)
  def logInfoData(o: AnyRef, message: Any)(data: => Any)
  def logEnterData(o: AnyRef, name: String, message: Any)(data: => Any)
  def logLeaveData(o: AnyRef, name: String, message: Any)(data: => Any)
  def logDebugData(o: AnyRef, message: Any)(data: => Any)

  protected final def make_message(o: Object, name: String, msg: Any, data: Any): String = {
    val klass = o.getClass
    val buf = new StringBuilder
    buf.append('[')
    buf.append(klass.getName)
    if (notNull(name)) {
      buf.append('.')
      buf.append(name)
    }
    buf.append(']')
    buf.append(' ')
    buf.append(msg.toString)
    if (data != None) {
      buf.append(' ')
      buf.append('{')
      make_data(data, buf)
      buf.append('}')
    }
    buf.toString
  }

  protected final def make_data(data: Any, buf: StringBuilder) {
    data match {
      case null => "null"
      case bytes: Array[Byte] => buf.append(bytes.toString)
      case s: String => {
        buf.append('"')
        make_string_data(data, buf)
        buf.append('"')
      }
      case _ => make_string_data(data, buf)
    }
  }

  protected final def make_string_data(data: Any, buf: StringBuilder) {
    com.asamioffice.goldenport.text.StringUtil.buildShortString(data.toString, 240, buf)
  }
}

// 2010-10-05
abstract class G3StandalonePlatform extends G3Platform {
  private lazy val http_client = {
    val params = new BasicHttpParams
    val schreg = new SchemeRegistry
    new DefaultHttpClient(
      new ThreadSafeClientConnManager(params, schreg),
      params)
  }

  override def open() {
  }

  override def close() {
    http_client.getConnectionManager.shutdown
  }

  def httpGet(get: http.GET): G3Event = {
    val resp = http_client.execute(
      http_host(get),
      http_get(get))

    if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
      new HttpEntityGETTED(get.uri, resp.getEntity())
    } else {
      error("XXX httpGet")
    }
  }

  private def http_host(get: http.GET) = {
    new HttpHost(get.uri, 80)
  }

  private def http_get(get: http.GET) = {
    error("")
  }

  def httpPut(put: http.PUT): G3Event = {
    error("XXX httpPut")
  }

  def httpPost(post: http.POST): G3Event = {
    error("XXX httpPut")
  }

  def httpDelete(delete: http.DELETE): G3Event = {
    error("XXX httpPut")
  }

  def httpMkcol(mkcol: http.MKCOL): G3Event = {
    error("XXX httpPut")
  }

  def httpCopy(copy: http.COPY): G3Event = {
    error("XXX httpPut")
  }

  def httpMove(move: http.MOVE): G3Event = {
    error("XXX httpPut")
  }

  def urlFetchString(url: URL, encoding: String): String = {
    val protocol = url.getProtocol()
    if ("http".equals(protocol) || "https".equals(protocol)) {
      val client = new DefaultHttpClient()
      var in: InputStream = null
      try {
        val httpMethod = new HttpGet(url.toURI);
        val response = client.execute(httpMethod)
        in = response.getEntity.getContent
        val bytes = UIO.stream2Bytes(in)
        new String(bytes, encoding)
      } finally {
        if (in != null) {
          in.close()
        }
        client.getConnectionManager().shutdown()
      }
    } else {
      var in = url.openStream()
      try {
        val bytes = UIO.stream2Bytes(in)
        new String(bytes, encoding)
      } finally {
        if (in != null) {
          in.close()
        }
      }
    }
  }

  override def createWebSocketDriver(path: String): G3WebSocketDriver = {
    new JettyWebSocketDriver()
  }
}

/*
package platforms {
  class PlainPlatform extends G3Platform {
  }
}
*/
